package com.qiguliuxing.dts.admin.service;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.entpay.EntPayBankRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayBankResult;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.service.WxPayService;
import com.qiguliuxing.dts.db.dao.DtsUserMapper;
import com.qiguliuxing.dts.db.domain.DtsMerchantAccount;
import com.qiguliuxing.dts.db.domain.DtsMerchantAccountTrace;
import com.qiguliuxing.dts.db.domain.DtsMerchantWithdrawalAccount;
import com.qiguliuxing.dts.db.domain.DtsUser;
import com.qiguliuxing.dts.service.merchant.BillStatisService;
import com.qiguliuxing.dts.service.merchant.WithdrawAccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;

@Service
public class AdminBillService {
    private static final Logger logger = LoggerFactory.getLogger(AdminBillService.class);

    @Resource
    private DtsUserMapper userMapper;

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private WithdrawAccountService withdrawAccountService;

    @Autowired
    private BillStatisService billStatisService;

    public boolean transfer(Integer userId, Integer money) {
        boolean result = false;
        DtsUser user = userMapper.selectByPrimaryKey(userId);
        if (user == null) {
            logger.error("微信用户不存在，异常结束！");
            return result;
        }
        String tradeNo = generateTradeNo(userId);
        EntPayRequest request = EntPayRequest.newBuilder()
                .partnerTradeNo(tradeNo)  // 商户订单号
                .openid(user.getWeixinOpenid()) // 用户openid
                .amount(money) // 金额,单位分
                .spbillCreateIp("120.25.25.170")
                .checkName(WxPayConstants.CheckNameOption.NO_CHECK)
                .description("佣金到零钱") // 描述，100字符限制
                .build();
        try {
            EntPayResult payResult = wxPayService.getEntPayService().entPay(request);
            logger.info("企业支付结果：{}", JSONObject.toJSONString(payResult));
            result = true;
        } catch (Exception ex) {
            logger.error("企业支付失败：{}", ex.getMessage());
            ex.printStackTrace();
        }
        return result;
    }

    public boolean payBank(String bankCode, String bankNo, String encTrueName, Integer amount) {
        boolean result = false;
        String tradeNo = generateTradeNo(2);
        EntPayBankRequest request = EntPayBankRequest.builder()
                .bankCode(bankCode)
                .amount(amount)
                .encBankNo(bankNo)
                .encTrueName(encTrueName)
                .partnerTradeNo(tradeNo)
                .description("提现到银行卡")
                .build();
        try {
            EntPayBankResult payResult = wxPayService.getEntPayService().payBank(request);
            logger.info("企业支付结果：{}", JSONObject.toJSONString(payResult));
            result = true;
        } catch (Exception ex) {
            logger.error("企业支付失败：{}", ex.getMessage());
            ex.printStackTrace();
        }
        return result;
    }

    public String getRandomNum(Integer num) {
        String base = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    private String generateTradeNo(Integer userId) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd");
        String now = df.format(LocalDate.now());
        String orderSn = now + getRandomNum(6);
        return userId + orderSn;
    }

    @Transactional(
            propagation = Propagation.REQUIRED,
            rollbackFor = {Exception.class}
    )
    public int approve(Integer traceId, String traceMsg, Byte status) {
        //1. 判断通过与否
        DtsMerchantAccountTrace dtsMerchantAccountTrace = withdrawAccountService.querySelective(traceId);
        if (status.intValue() == 1) {
            payment(dtsMerchantAccountTrace);
        } else {
            dtsMerchantAccountTrace.setStatus((byte)0);
        }
        //5. 判断通过与否写入数据库
        dtsMerchantAccountTrace.setTraceMsg(traceMsg);
        return withdrawAccountService.updateByPrimaryKey(dtsMerchantAccountTrace);
    }

    private void payment(DtsMerchantAccountTrace dtsMerchantAccountTrace) {
        BigDecimal amount = dtsMerchantAccountTrace.getAmount();
        //2. 查询账户信息
        DtsMerchantWithdrawalAccount withdrawAccount = withdrawAccountService.getWithdrawAccount(dtsMerchantAccountTrace.getBrandId(), dtsMerchantAccountTrace.getAccountNo());
        //3. 账户相关的核减
        DtsMerchantAccount accountByBrandId = billStatisService.getAccountByBrandId(dtsMerchantAccountTrace.getBrandId());
        //4. 账户总额
        BigDecimal remainAmount = accountByBrandId.getRemainAmount();
        //4. 核减后账户总额
        BigDecimal afterAmount = remainAmount.subtract(amount);
        accountByBrandId.setRemainAmount(afterAmount);
        accountByBrandId.setUpdateTime(LocalDateTime.now());
        //4. 转入相关的账户
        Integer payType = withdrawAccount.getPayType();
        if (payType ==1) {
        // 转入微信
            transfer(Integer.parseInt(withdrawAccount.getAccount()), amount.intValue());
        } else {
        // 转入bank
            payBank(withdrawAccount.getDepositBank(), withdrawAccount.getAccount(), withdrawAccount.getRealName(), amount.intValue());
        }
        dtsMerchantAccountTrace.setBeforeAmount(remainAmount);
        dtsMerchantAccountTrace.setAfterAmount(afterAmount);
        dtsMerchantAccountTrace.setFinishTime(LocalDateTime.now());
        dtsMerchantAccountTrace.setStatus((byte)1);
        billStatisService.subtractRemainAmount(accountByBrandId);
    }
}
